package trading.algo.BullToBearTask;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import trading.algo.CancelOrderMasterTask;
import trading.algo.OpenOrdersTask;
import trading.algo.STKBuyOrderTask;
import trading.algo.STKShortSellingTask;
import trading.algo.TimerKillerTask;
import trading.algo.UpdateAccountValueTask;
import trading.bo.DBAccessorBO;
import trading.bo.EmailAccessorBO;
import trading.bo.IBAccessorBO;
import trading.dataentry.StockPositionOrOrder;
import trading.util.OrderSplitHelper;

public class PositionCleanUpTask extends TimerTask {

    private IBAccessorBO ibAccessorBO;
    private DBAccessorBO dbAccessorBO;
    private EmailAccessorBO emailAccessorBO;
    private OrderSplitHelper orderSplitHelper;

    public PositionCleanUpTask(IBAccessorBO ibAccessorBO,
            DBAccessorBO dbAccessorBO, EmailAccessorBO emailAccessorBO,
            OrderSplitHelper orderSplitHelper) {
        this.ibAccessorBO = ibAccessorBO;
        this.dbAccessorBO = dbAccessorBO;
        this.emailAccessorBO = emailAccessorBO;
        this.orderSplitHelper = orderSplitHelper;
    }

    @Override
    public void run() {
        List<StockPositionOrOrder> stockPositions = this.dbAccessorBO
                .getPortfolioStockPositions();
        List<StockPositionOrOrder> openOrders = this.dbAccessorBO
                .getOpenNonTrailStockOrder();
        openOrders.addAll(this.dbAccessorBO.getOpenTrailOrder());

        // No action if it's already cleaned up
        if (stockPositions.size() == 0 && openOrders.size() == 0) {
            return;
        }

        // Step 1: cancel all open orders
        Timer timer = new Timer();
        int taskID = 0;
        CancelOrderMasterTask cancelOrderTask = new CancelOrderMasterTask(ibAccessorBO, dbAccessorBO, emailAccessorBO);
        timer.schedule(cancelOrderTask, taskID * 1000);
        taskID += 15;

        // Step 2: create markat order for all open positions
        for (int i = 0; i < stockPositions.size(); i++, taskID += 2) {
            StockPositionOrOrder position = stockPositions.get(i);
            int size = Integer.parseInt(position.getQuantity());
            if (size < 0) {
                STKBuyOrderTask task = new STKBuyOrderTask(size * -1,
                        position.getTicker(), this.ibAccessorBO,
                        emailAccessorBO, orderSplitHelper, true);
                timer.schedule(task, taskID * 1000);
            } else {
                STKShortSellingTask task = new STKShortSellingTask(
                        position.getTicker(), size, this.ibAccessorBO,
                        emailAccessorBO, this.orderSplitHelper, true);
                timer.schedule(task, taskID * 1000);
            }
        }

        // Step 3: update open order and portfolio positions
        // wait for 10 mins for last batch of position cleaning to finish
        taskID += 600;
        OpenOrdersTask openOrderTask = new OpenOrdersTask(this.ibAccessorBO,
                this.dbAccessorBO);
        timer.schedule(openOrderTask, taskID * 1000);
        taskID += 2;

        timer.schedule(new UpdateAccountValueTask(ibAccessorBO, dbAccessorBO, true),
                taskID * 1000);
        taskID += 5;

        // Step 4: rerun this task to make sure it is actually cleaned up
        // Note: this is like a recursion, the ending condition is when it's all
        // cleaned up
        PositionCleanUpTask positionCleanUpTask = new PositionCleanUpTask(
                ibAccessorBO, dbAccessorBO, emailAccessorBO, orderSplitHelper);
        timer.schedule(positionCleanUpTask, taskID * 1000);

        taskID += 15;

        // Step 5: kill timer
        TimerKillerTask timerKillerTask = new TimerKillerTask(timer);
        timer.schedule(timerKillerTask, taskID * 1000);
    }

}
